package com.app.system.permission.web;

import com.app.log.annotation.MyLog;
import com.app.log.service.LogSystemService;
import com.app.system.common.EncipherPwd;
import com.app.system.config.jwt.JwTUtils;
import com.app.system.config.jwt.JwtToken;
import com.app.system.config.properties.SystemParamProperties;
import com.app.system.config.requestLimit.RequestLimit;
import com.app.system.permission.en.Status;
import com.app.system.permission.model.SysPermission;
import com.app.system.permission.model.SysRole;
import com.app.system.permission.model.UserInfo;
import com.app.system.permission.service.DataDictService;
import com.app.system.permission.service.UserInfoService;
import com.app.system.utils.CollectionUtils;
import com.app.system.utils.ParamUtils;
import com.app.system.utils.WebUtils;
import com.app.system.utils.dataType.IntegerUtils;
import com.app.system.utils.dataType.StringUtils;
import com.app.system.utils.encrypt.EncryptUtil;
import com.app.system.utils.exception.Response;
import com.app.system.utils.upload.UploadInfo;
import com.app.system.utils.upload.UploadInfoUtil;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 系统登录
 * Created by wcf-pc on 2018/5/15.
 *
 * @author wcf-pc
 */
@RestController
@SuppressWarnings("all")
public class AppController {

    @Resource
    private LogSystemService logSystemService;
    @Resource
    private UserInfoService userInfoService;
    @Resource
    private DataDictService dataDictService;
    @Resource
    private SystemParamProperties systemParamProperties;
    @Autowired
    private EncipherPwd encipherPwd;

    @RequestMapping("/app/checkAndRefreshToken")
    public Map checkAndRefreshToken(HttpServletRequest request) {
        String token = ParamUtils.getString(request, "token", "");
        DecodedJWT jwt = JwTUtils.getDecodedJWT(token);
        Map<String, Object> resultMap = Maps.newHashMap();
        if (jwt == null) {
            resultMap.put("status", "no");
            resultMap.put("token", "");
            return resultMap;
        } else {
            String username = JwTUtils.getUsername(token);
            UserInfo user = this.userInfoService.findByUsername(username);

            String passwordEncode = ParamUtils.getString(request, "password", "");//前端传递的加密后的密码
            EncryptUtil encryptUtil = new EncryptUtil();
            String passwordDecode = encryptUtil.DESdecode(passwordEncode, EncryptUtil.KEY);//解密后的密码

            String hashAlgorithmName = systemParamProperties.getHashedCredentialsMatcherHashAlgorithmName();//加密方式
            String crdentials = passwordDecode;//密码原值
            ByteSource credentialsSalt = ByteSource.Util.bytes(user.getUsername() + user.getSalt());//以账号+salt作为盐值
            int hashIterations = systemParamProperties.getHashedCredentialsMatcherHashIterations();//加密1024次
            String newPassword = new SimpleHash(hashAlgorithmName, crdentials, credentialsSalt, hashIterations).toString();
            if (newPassword.equals(user.getPassword())) {//验证一致，更新token
                Date expiresDate = jwt.getExpiresAt();//有效期7天
                Date issuedDate = jwt.getIssuedAt();
                long intervalTime = 1 * 24 * 60 * 60 * 1000;//不足1天，执行更新token操作
                long chaTime = expiresDate.getTime() - issuedDate.getTime();
                if (chaTime <= intervalTime) {
                    String newToken = JwTUtils.sign(user.getUsername(), user.getPassword());
                    resultMap.put("status", "ok");
                    resultMap.put("token", newToken);
                    return resultMap;
                } else {
                    resultMap.put("status", "no");
                    resultMap.put("token", "");
                    return resultMap;
                }

            } else {
                resultMap.put("status", "logout");//请重新登录，此期间应是密码进行了修改，需要提醒用户登录
                resultMap.put("token", "");
            }
            return resultMap;
        }
    }

    @PostMapping("/app/appValidate")
    @RequestLimit
    public Map appValidate(HttpServletRequest request) {
        String username = ParamUtils.getString(request, "username", "");
        String password = ParamUtils.getString(request, "password", "");
        String clientID = ParamUtils.getString(request, "clientID", "");
        Map<String, Object> map = Maps.newHashMap();
        String message = "";
        int status = 0;
        UserInfo user = this.userInfoService.findByUsername(username);
        try {
            String hashAlgorithmName = systemParamProperties.getHashedCredentialsMatcherHashAlgorithmName();//加密方式
            String crdentials = password;//密码原值
            ByteSource credentialsSalt = ByteSource.Util.bytes(user.getUsername() + user.getSalt());//以账号+salt作为盐值
            int hashIterations = systemParamProperties.getHashedCredentialsMatcherHashIterations();//加密1024次
            Object result = new SimpleHash(hashAlgorithmName, crdentials, credentialsSalt, hashIterations);

            String token = JwTUtils.sign(user.getUsername(), result.toString());
            SecurityUtils.getSubject().login(new JwtToken(token));

            message = "登录成功";
            //更新客户端ID，用于以后信息推送使用
            if (StringUtils.isNotEmpty(clientID)) {
                user.setClientID(clientID);
                this.userInfoService.save(user);
            }
            EncryptUtil encryptUtil = new EncryptUtil();
            map.put("password", encryptUtil.DESencode(password, EncryptUtil.KEY));//加密后的密码，返回前端
            map.put("token", token);
            logSystemService.addLog(request, username, "【app端】用户登录", "com.app.system.permission.web.LoginController.appValidate");
        } catch (Exception uae) {
            message = "用户名或密码不正确";
            status = 1;
        }
        map.put("status", status);
        map.put("message", message);
        return map;
    }

    @RequestMapping("/app/sysPermission")
    public Map getUserSysPermission(HttpServletRequest request) {
        String credentials = (String) SecurityUtils.getSubject().getPrincipal();
        String username = JwTUtils.getUsername(credentials);
        UserInfo userInfo = this.userInfoService.findByUsername(username);
        Map map = Maps.newHashMap();
        List<String> list = Lists.newArrayList();
        Integer state = Status.NO.getIndex();//初始定义账号有效状态为'无效'
        state = userInfo == null ? state : userInfo.getState();
        if (state == Status.YES.getIndex()) {
            for (SysRole role : userInfo.getRoleList()) {
                //无效
                if (!role.getAvailable()) {
                    continue;
                }
                for (SysPermission p : role.getPermissions()) {
                    if (p.getEnabled() == 0 && p.getMenuType() != null && p.getMenuType() == 2) {//禁用
                        if (!StringUtils.isEmpty(p.getPermission())) {
                            List<String> permissionList = Lists.newArrayList(p.getPermission().split(";"));
                            if (CollectionUtils.isNotEmpty(permissionList)) {
                                list.addAll(permissionList);
                            }
                        }
                    }
                }
            }
        }
        map.put("permissions", list);
        return map;
    }

    /**
     * app修改个人信息
     *
     * @return
     */
    @RequestMapping("/app/loadForm")
    public Map loadForm(HttpServletRequest request) {
        String credentials = (String) SecurityUtils.getSubject().getPrincipal();
        String username = JwTUtils.getUsername(credentials);
        UserInfo userInfo = this.userInfoService.findByUsername(username);
        Map data = Maps.newHashMap();
        data.put("username", StringUtils.getNotNull(userInfo.getUsername()));
        data.put("name", StringUtils.getNotNull(userInfo.getName()));
        data.put("telPhone", StringUtils.getNotNull(userInfo.getTelPhone()));
        data.put("pic", StringUtils.getNotNull(userInfo.getPic()));
        data.put("id", IntegerUtils.getNotNull(userInfo.getId()));
        Map map = Maps.newHashMap();
        map.put("dptName", userInfo.getDepartment().getName());
        map.put("data", data);
        map.put("pic", WebUtils.getSystemAccess() + userInfo.getPic());
        return map;
    }

    /**
     * 上传头像
     *
     * @return
     */
    @RequestMapping("/app/uploadHeadPic")
    public synchronized Response uploadHeadPic(HttpServletRequest request) {
        Response response;
        int userId = ParamUtils.getInt(request, "userId", 0);
        UserInfo userInfo = userInfoService.findOneById(userId);
        if (userInfo == null) {
            response = Response.fail();
        } else {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
            // 路径
            String path = systemParamProperties.getUploadFolder() + "head/";
            String parameterName = "icon_" + userInfo.getId() + sdf.format(new Date());
            UploadInfo uploadInfo = UploadInfoUtil.uploadFile(request, path, "file", parameterName, true, 200, 200);
            // 上传文件路径
            String filePath = systemParamProperties.getStaticAccessPath() + "head/" + uploadInfo.getSaveFilename();
            userInfo.setPic(filePath);
            userInfoService.save(userInfo);
            response = new Response("0001", "上传成功");
            response.setData(WebUtils.getSystemAccess() + "/" + userInfo.getPic());
        }

        return response;
    }

    /**
     * 保存个人信息
     *
     * @param request
     * @return
     */
    @MyLog(value = "app个人信息管理-个人信息保存")
    @RequestMapping("/app/saveUserInfo")
    public synchronized Response saveUserInfo(HttpServletRequest request) {
        String name = ParamUtils.getString(request, "name", "");
        String telPhone = ParamUtils.getString(request, "telPhone", "");

        String credentials = (String) SecurityUtils.getSubject().getPrincipal();
        String username = JwTUtils.getUsername(credentials);
        UserInfo userInfo = this.userInfoService.findByUsername(username);
        Response response = new Response("0001", "保存成功");
        if (userInfo == null) {
            response = Response.fail();
        } else {
            userInfo.setName(name);
            userInfo.setTelPhone(telPhone);

            userInfoService.save(userInfo);
        }

        response.setData(userInfo.getId());

        return response;
    }

    /**
     * 密码修改
     *
     * @param request
     * @return
     */
    @MyLog(value = "app个人信息管理-个人修改密码")
    @RequestMapping("/app/savePassword")
    public Response savePassword(HttpServletRequest request) {
        String oldPwd = ParamUtils.getString(request, "oldPassword", "");
        String newPwd = ParamUtils.getString(request, "newPassword", "");
        String password = ParamUtils.getString(request, "password", "");

        Object obj = SecurityUtils.getSubject().getPrincipal();
        if (obj == null) {
            return new Response("0000", "未登录用户");
        }

        if (!newPwd.equals(password)) {
            return new Response("0000", "密码输入不一致");
        }

        String username = JwTUtils.getUsername(String.valueOf(obj));
        UserInfo userInfo = this.userInfoService.findByUsername(username);
        if (userInfo == null) {
            return new Response("0000", "无效用户");
        }
        Map<String, String> map = null;
        String encipherPassword = null, encipherSalt = null;
        //比对原始密码正确性
        encipherPassword = encipherPwd.getCredentialsPwd(username, oldPwd, userInfo.getSalt());
        if (!encipherPassword.equals(userInfo.getPassword())) {
            return new Response("0000", "原始密码输入有误");
        }

        //产生新的秘钥
        map = encipherPwd.getEncipherPwd(username, newPwd);
        encipherPassword = map.get("password");
        encipherSalt = map.get("salt");
        //更新密码
        this.userInfoService.updatePwd(userInfo.getId(), encipherPassword, encipherSalt);

        return new Response("0001", "密码修改成功");
    }
}
